package xyz.labmem.base.core.tool

import org.springframework.aop.framework.AdvisedSupport
import org.springframework.aop.framework.AopProxy
import org.springframework.aop.support.AopUtils

/**
 * 代理对象获取工具
 * @Author lty
 * @Date 2021/12/15 13:44
 */

@Throws(Exception::class)
fun Any?.getProxyTarget(): Any? {
    var proxy = this
    if (!AopUtils.isAopProxy(proxy)) {
        return proxy
    }
    proxy = (if (AopUtils.isJdkDynamicProxy(proxy)) {
        getJdkDynamicProxyTargetObject(proxy)
    } else {
        getCglibProxyTargetObject(proxy)
    })
    return proxy.getProxyTarget()
}

@Throws(Exception::class)
private fun getCglibProxyTargetObject(proxy: Any?): Any? {
    if (AopUtils.isAopProxy(proxy)) {
        val h = proxy!!.javaClass.getDeclaredField("CGLIB\$CALLBACK_0")
        h.isAccessible = true
        val dynamicAdvisedInterceptor = h[proxy]
        val advised = dynamicAdvisedInterceptor.javaClass.getDeclaredField("advised")
        advised.isAccessible = true
        return (advised[dynamicAdvisedInterceptor] as AdvisedSupport).targetSource.target
    }
    return proxy
}

@Throws(Exception::class)
private fun getJdkDynamicProxyTargetObject(proxy: Any?): Any? {
    val h = proxy!!.javaClass.superclass.getDeclaredField("h")
    h.isAccessible = true
    val aopProxy = h[proxy] as AopProxy
    val advised = aopProxy.javaClass.getDeclaredField("advised")
    advised.isAccessible = true
    return (advised[aopProxy] as AdvisedSupport).targetSource.target
}
